<template>
	<div class="blog-toc-container">
		<h2>文章目录索引</h2>
		<right-list :list="tocWithIsSelect" @select="handleSelect"></right-list>
	</div>
</template>

<script>
import RightList from './RightList.vue'
import debounce from '@/utils/debounce'
export default {
	name: 'BlogToc',
	components: { RightList },
	data() {
		return {
			currentAnchor: '', // 在刷新后还可以用
		}
	},
	props: {
		toc: {
			type: Array,
			default: () => [],
		},
	},
	created() {
		this.setSelectDebounce = debounce(this.setSelect, 100)
		this.$bus.$on('mainScroll', this.setSelectDebounce)
	},
	destroyed() {
		this.$bus.$off('mainScroll', this.setSelectDebounce)
	},
	methods: {
		handleSelect(item) {
			location.hash = '#' + item.anchor
		},
		setSelect(scrollDom) {
			if (!scrollDom) {
				return
			}
			this.currentAnchor = ''
			const range = 200
			for (let dom of this.doms) {
				if (!dom) {
					continue
				}
				const top = dom.getBoundingClientRect().top // 得到元素到视口顶部距离
				if (top > 0 && top <= range) {
					// 在规定范围内
					this.currentAnchor = dom.id
					return
				} else if (top > range) {
					// 在规定返回下方
					return
				} else {
					// 在规定返回上方
					this.currentAnchor = dom.id
				}
			}
		},
	},
	computed: {
		// 根据toc属性和data里面的currentAnchor得到带有isSelect属性的数组
		tocWithIsSelect() {
			const getToc = (toc = []) => {
				return toc.map((item) => ({
					...item,
					isSelect: item.anchor === this.currentAnchor,
					children: getToc(item.children),
				}))
			}
			return getToc(this.toc)
		},
		// 根据toc得到对应元素数组，只有拿到DOM元素才能找到位置
		doms() {
			const doms = []
			const addToDoms = (toc) => {
				toc.forEach((item) => {
					doms.push(document.getElementById(item.anchor))
					if (item.children && item.children.length) {
						addToDoms(item.children)
					}
				})
			}
			addToDoms(this.toc)
			return doms
		},
	},
}
</script>

<style lang="less" scoped>
.blog-toc-container {
	width: 300px;
	height: 100%;
	padding: 20px;
	overflow: auto;
	position: relative;
	h2 {
		font-weight: 700;
		letter-spacing: 2px;
		font-size: 1em;
		margin-bottom: 20px;
	}
}
</style>
